package cn.smile.business.core.impl;

import cn.smile.bean.dto.basic.ExpenseBillDTO;
import cn.smile.bean.dto.basic.TopUpBillDTO;
import cn.smile.bean.dto.core.HomeTopDTO;
import cn.smile.bean.dto.core.MiniProjectHomeDTO;
import cn.smile.bean.dto.core.RecentDataCountDTO;
import cn.smile.bean.form.basic.bill.QueryExpenseForm;
import cn.smile.bean.form.basic.bill.QueryTopUpForm;
import cn.smile.business.basic.IExpenseBillService;
import cn.smile.business.basic.IMemberService;
import cn.smile.business.basic.ITopUpBillService;
import cn.smile.business.core.IHomeService;
import cn.smile.commons.constant.CommonConstant;
import cn.smile.commons.enums.basic.MiniProjectCountEnum;
import cn.smile.utils.DateFormatUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import oshi.SystemInfo;
import oshi.hardware.GlobalMemory;

import jakarta.annotation.Resource;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class HomeServiceImpl implements IHomeService {
    @Resource
    private IMemberService memberService;
    @Resource
    private IExpenseBillService expenseService;
    @Resource
    private ITopUpBillService topUpBillService;

    @Override
    public HomeTopDTO getHomeTop() {
        log.info("[HomeServiceImpl].[getHomeTop] ------> Web首页 TOP 栏数据统计 Start");
        HomeTopDTO dto = new HomeTopDTO();
        dto.setJvmMemory(this.getJvmMemory());
        dto.setIntStoUsageRate(this.getIntStoRatio());
        log.info("[HomeServiceImpl].[getHomeTop] ------> Web首页 TOP 栏数据统计 End, dto = {}", JSON.toJSONString(dto));
        return dto;
    }

    @Override
    public MiniProjectHomeDTO getMiniProjectHome(MiniProjectCountEnum countEnum) {
        log.info("[HomeServiceImpl].[getMiniProjectHome] ------> 微信小程序首页统计 Start, countEnum = {}", countEnum);
        MiniProjectHomeDTO dto = new MiniProjectHomeDTO();
        dto.setMemberNum(memberService.countMemberByShop());
        BigDecimal expenseAmount = expenseService.countExpenseAmount(countEnum);
        BigDecimal topUpAmount = topUpBillService.countTopUpAmount(countEnum);
        dto.setTopUpAmount(topUpAmount);
        BigDecimal earning = expenseAmount.add(topUpAmount);
        dto.setEarning(earning);
        log.info("[HomeServiceImpl].[getMiniProjectHome] ------> 微信小程序首页统计 End");
        return dto;
    }

    @Override
    public RecentDataCountDTO countRecentData() {
        log.info("[HomeServiceImpl].[countRecentData] ------> 最近7天数据统计 Start");
        RecentDataCountDTO dto = new RecentDataCountDTO();
        dto.setDays(DateFormatUtil.getRecentDays());
        //统计金额数据
        Date nowTime = new Date();
        String timeStart = DateFormatUtil.getCountStartTime(nowTime, MiniProjectCountEnum.LAST_SEVEN_DAYS);
        String timeEnd = DateFormatUtil.parseDateToStr(nowTime, DateFormatUtil.TO_DATE_END);
        this.getExpenseList(timeStart, timeEnd, dto);
        this.getTopUpList(timeStart, timeEnd, dto);
        log.info("[HomeServiceImpl].[countRecentData] ------> 最近7天数据统计 End");
        return dto;
    }

    /**
     * 查询消费金额
     *
     * @param startTime 查询开始时间
     * @param endTime   查询结果时间
     * @param dto       数据存储对象
     */
    private void getExpenseList(String startTime, String endTime, RecentDataCountDTO dto) {
        QueryExpenseForm form = new QueryExpenseForm();
        form.setQueryTimeStart(startTime);
        form.setQueryTimeEnd(endTime);
        List<ExpenseBillDTO> dataList = expenseService.getList(form);
        Map<String, BigDecimal> memberExpenseMap = Maps.newHashMap();
        Map<String, BigDecimal> notMemberExpenseMap = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(dataList)) {
            for (ExpenseBillDTO entity : dataList) {
                String day = String.format("%s日", entity.getBillTime().getDayOfMonth());
                if (ObjectUtils.isEmpty(entity.getMemberId())) {
                    notMemberExpenseMap.put(day, notMemberExpenseMap.getOrDefault(day, CommonConstant.DEFAULT_PRICE).add(entity.getFinalPrice()));
                } else {
                    memberExpenseMap.put(day, memberExpenseMap.getOrDefault(day, CommonConstant.DEFAULT_PRICE).add(entity.getFinalPrice()));
                }
            }
        }
        for (String day : dto.getDays()) {
            dto.getMemberExpAmountList().add(memberExpenseMap.getOrDefault(day, CommonConstant.DEFAULT_PRICE));
            dto.getNotMemberExpAmountList().add(notMemberExpenseMap.getOrDefault(day, CommonConstant.DEFAULT_PRICE));
        }
    }

    /**
     * 查询充值金额
     *
     * @param startTime 查询开始时间
     * @param endTime   查询结果时间
     * @param dto       数据存储对象
     */
    private void getTopUpList(String startTime, String endTime, RecentDataCountDTO dto) {
        QueryTopUpForm form = new QueryTopUpForm();
        form.setQueryTimeStart(startTime);
        form.setQueryTimeEnd(endTime);
        List<TopUpBillDTO> dataList = topUpBillService.getList(form);
        Map<String, BigDecimal> topUpMap = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(dataList)) {
            for (TopUpBillDTO entity : dataList) {
                String day = String.format("%s日", entity.getBillTime().getDayOfMonth());
                topUpMap.put(day, topUpMap.getOrDefault(day, CommonConstant.DEFAULT_PRICE).add(entity.getTopUpPrice()));
            }
        }
        for (String day : dto.getDays()) {
            dto.getTopUpAmountList().add(topUpMap.getOrDefault(day, CommonConstant.DEFAULT_PRICE));
        }
    }

    /**
     * 获取 JVM 内存
     *
     * @return 已使用/最大可用内存
     */
    private String getJvmMemory() {
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        // 椎内存使用情况
        MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage();
        // 最大可用内存
        long maxMemorySize = memoryUsage.getMax();
        // 已使用的内存
        long usedMemorySize = memoryUsage.getUsed();
        return new DecimalFormat("#.##").format((usedMemorySize * 1.0 / maxMemorySize) * 100);
    }

    /**
     * 获取 内存 使用率
     *
     * @return 使用率
     */
    private String getIntStoRatio() {
        SystemInfo info = new SystemInfo();
        GlobalMemory memory = info.getHardware().getMemory();
        long total = memory.getTotal();
        long available = memory.getAvailable();
        return new DecimalFormat("#.##").format(((total - available) * 1.0 / total) * 100);
    }
}
